//
// Created by 33145 on 2023/5/28.
//
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <memory>
#include "../rocket/common/log.h"
#include "../rocket/common/config.h"
#include "../rocket/net/fdevent.h"
#include "../rocket/net/eventloop.h"
#include "../rocket/net/timer.h"
#include "../rocket/net/io_thread_group.h"

void test_eventloop() {
  rocket::EventLoop* eventLoop = new rocket::EventLoop();

  int listenfd = socket(AF_INET, SOCK_STREAM, 0);
  if (listenfd == -1) {
    LOG_ERROR("listenfd = -1");
    exit(0);
  }
  sockaddr_in addr{};
  memset(&addr, 0, sizeof(sockaddr_in));
  addr.sin_port = htons(12345);
  addr.sin_family = AF_INET;
  inet_aton("127.0.0.1", &addr.sin_addr);

  int rt = bind(listenfd, reinterpret_cast<sockaddr*>(&addr), sizeof(sockaddr_in));
  if (rt != 0) {
    LOG_ERROR("bind error");
    exit(1);
  }
  rt = listen(listenfd, 5);
  if (rt != 0) {
    LOG_ERROR("listen error");
    exit(1);
  }

  rocket::FdEvent event(listenfd);
  event.listen(rocket::FdEvent::IN_EVENT, [listenfd](){
    sockaddr_in peer_addr{};
    socklen_t addr_len = 0;
    memset(&peer_addr, 0, sizeof(sockaddr_in));
    int clientfd = accept(listenfd, reinterpret_cast<sockaddr*>(&peer_addr), &addr_len);
    LOG_DEBUG("success get client [%s:%d]", inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));
    printf("success get client [%s:%d]\n", inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));
  });
  eventLoop->addEpollEvent(&event);

  eventLoop->loop();
}

void test_io_thread() {
  int listenfd = socket(AF_INET, SOCK_STREAM, 0);
  if (listenfd == -1) {
    LOG_ERROR("listenfd = -1");
    exit(0);
  }

  sockaddr_in addr{};

  addr.sin_port = htons(12345);
  addr.sin_family = AF_INET;
  inet_aton("127.0.0.1", &addr.sin_addr);

  int rt = bind(listenfd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
  if (rt != 0) {
    LOG_ERROR("bind error");
    exit(1);
  }

  rt = listen(listenfd, 100);
  if (rt != 0) {
    LOG_ERROR("listen error");
    exit(1);
  }

  rocket::FdEvent event(listenfd);
  event.listen(rocket::FdEvent::IN_EVENT, [listenfd]() {
    sockaddr_in peer_addr{};
    socklen_t addr_len = sizeof(peer_addr);
    memset(&peer_addr, 0, sizeof(peer_addr));
    int clientfd = accept(listenfd, reinterpret_cast<sockaddr*>(&peer_addr), &addr_len);

    LOG_INFO("success get client fd[%d], peer addr: [%s:%d]", clientfd, inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));
  });

  int i = 0;
  rocket::TimerEvent::ptr timer_event = std::make_shared<rocket::TimerEvent> (
          1000, [&i]() {
            LOG_INFO("trigger timer event, count=%d", i++);
          }, true);

  rocket::IOThreadGroup io_thread_group(2);
  rocket::IOThread::ptr io_thread = io_thread_group.getIOThread();
  io_thread->getEventLoop()->addEpollEvent(&event);
  io_thread->getEventLoop()->addTimerEvent(timer_event);

  rocket::IOThread::ptr io_thread2 = io_thread_group.getIOThread();
  io_thread2->getEventLoop()->addTimerEvent(timer_event);

  io_thread_group.start();
  io_thread_group.join();
}

int main() {
  rocket::Config::SetGlobalConfig("/home/orange/tinytinyRPC/conf/rocket.xml");
  rocket::Logger::InitGlobalLogger(0);

  test_io_thread();

  return 0;
}